//#include <can_config.h>

#include <errno.h>
#include <getopt.h>
#include <libgen.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <net/if.h>

#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <poll.h>

#include <linux/can.h>
#include <linux/can/raw.h>

extern int optind, opterr, optopt;

static void print_usage(char *prg)
{
	fprintf(stderr,
		"Usage: %s [<can-interface>] [Options] <can-msg>\n"
		"<can-msg> can consist of up to 8 bytes given as a space separated list\n"
		"Options:\n"
		" -i, --identifier=ID	CAN Identifier (default = 1)\n"
		" -r  --rtr		send remote request\n"
		" -e  --extended	send extended frame\n"
		" -l			send message infinite times\n"
		"     --loop=COUNT	send message COUNT times\n"
		" -p  --poll		use poll(2) to wait for buffer space while sending\n"
		" -v, --verbose		be verbose\n"
		" -h, --help		this help\n"
		"     --version		print version information and exit\n",
		prg);
}

enum {
		VERSION_OPTION = CHAR_MAX + 1,
};

typedef enum
{
	RETURN_BACK,
	MOVE,
	STOP
}EN_ELE_CTL_OPCODE;

typedef struct _can_gram
{
	char opcode;
	char param;
	char reserved[6];
}can_gram;

#define SID_LECPA1 (0x301)
#define SID_CAP (0x303)
#define SID_QPCR (0x306)

#define SID_Thermal (0x305)

#define ACT_SID(sid) (((sid&0x1f)<<6)+2)
#define ACT_EID(sid,tcw) (((sid&0x60)<<8) + tcw)


#define FILE_STR "tecanStr.txt"


int sendString(unsigned short sid, int len, unsigned char * buff, int canInterface,unsigned int *sumOut)
{
    int sizeLeft = len;
    struct can_frame frameToSend;
    unsigned char * ptrData = buff;

    frameToSend.can_id = sid;
    int ret = 0;
    int sendBytes = 0;
	unsigned int sumTemp = 0;
	unsigned short sumOnce = 0;

    while(sizeLeft>0)
    {
        if(sizeLeft>=8)
        {
            frameToSend.can_dlc = 8;
			sumOnce = 0;
            memcpy(frameToSend.data,ptrData,8);
		    sumOnce += ptrData[0] + ptrData[7];
			sumOnce += ptrData[1] + ptrData[6];
			sumOnce += ptrData[2] + ptrData[5];
			sumOnce += ptrData[3] + ptrData[4];
			sumTemp += sumOnce;
            ptrData += 8;
            sizeLeft-=8;
            ret = write(canInterface, &frameToSend, sizeof(struct can_frame));

            if(ret>0)
            {
               sendBytes+= frameToSend.can_dlc;
            }
            else
            {
				//printf("send through can failed\n");
				perror("send through can failed\n");
                return sendBytes;
            }
        }
        else 
        {
            frameToSend.can_dlc = sizeLeft;
            memcpy(frameToSend.data,ptrData,sizeLeft);
			int i = 0;
			sumOnce = 0;
			for(i=0;i<sizeLeft;i++)
			{
				sumOnce += ptrData[i];
			}
			sumTemp += sumOnce;			
            ptrData += sizeLeft;
            sizeLeft-=sizeLeft;
            ret = write(canInterface, &frameToSend, sizeof(struct can_frame));

            if(ret>0)
            {
               sendBytes+= frameToSend.can_dlc;
            }
            else
            {
				//printf("send through can failed\n");
				perror("send through can failed\n");
                return sendBytes;
            }
        }
		usleep(1000);
    }
    *sumOut = sumTemp;
    return sendBytes;
}
#define SOCA_FRAME_TAIL 0x03
#define SOCA_FRAME_HEADER 0x02
#define SEQNUM 0x31
#define SOCAID 0x33

int sendToTecan(int socaid,unsigned char *data, int len, int canInterface)
{
	unsigned char * sendData = (unsigned char *)malloc(sizeof(char)*(len + 5));
	int sendBytes = 0;
    sendData[0] = 0x02;//header
	sendData[1] = SOCAID;//SOCA ID Fixed
	sendData[2] = 0x31;//Seq Num, Fixed, no used
	sendData[len+3] = SOCA_FRAME_TAIL;//tail

	memcpy(sendData+3,data,len);
	//calculate check sum
	sendData[len+4] = sendData[0];//checksum, CAN no need

	for (int i = 1; i < (len+4); i++)
                sendData[len+4] = (unsigned char)(sendData[len+4] ^ sendData[i]);
    unsigned int sumOnce = 0;
    sendBytes = sendString(socaid,len + 5,sendData,canInterface,&sumOnce);

    free(sendData);
	return sendBytes;
}

unsigned int calcStrSum(int lenIn, unsigned char * strIn)
{
	unsigned int sumTmp = 0;

	int lenLeft = lenIn - 1;


	while(lenLeft >= 0)
	{
		sumTmp += strIn[lenLeft];
		lenLeft--;
	}

	return sumTmp;
}

int main(int argc, char **argv)
{
	struct can_frame frame = {
		.can_id = 0x306,//for qpcr1
	};
	struct ifreq ifr;
	struct sockaddr_can addr;
	char *interface;
	int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW;
	int loopcount = 1, infinite = 0;
	int s, opt, ret, i, dlc = 0, rtr = 0, extended = 0;
	ssize_t len;
	int use_poll = 0;
	int verbose = 0;

	unsigned char strBuff[1024] = {0};
	int lenStr = 0;

	FILE * fp = fopen("/mnt/nandflash/apps/tmp/qpcr1_scheme.txt","r");

	if(fp==NULL)
	{
		printf("open file failed\n");
		return 1;
	}

	struct option long_options[] = {
		{ "help",	no_argument,		0, 'h' },
		{ "poll",	no_argument,		0, 'p'},
		{ "identifier",	required_argument,	0, 'i' },
		{ "rtr",	no_argument,		0, 'r' },
		{ "extended",	no_argument,		0, 'e' },
		{ "version",	no_argument,		0, VERSION_OPTION},
		{ "verbose",	no_argument,		0, 'v'},
		{ "loop",	required_argument,	0, 'l'},
		{ 0,		0,			0, 0 },
	};


	 	

	while ((opt = getopt_long(argc, argv, "hpvi:lre", long_options, NULL)) != -1) {
		switch (opt) {
		case 'h':
			print_usage(basename(argv[0]));
			exit(0);

		case 'p':
			use_poll = 1;
			break;

		case 'v':
			verbose = 1;
			break;

		case 'l':
			if (optarg)
				loopcount = strtoul(optarg, NULL, 0);
			else
				infinite = 1;
			break;
		case 'i':
			frame.can_id = strtoul(optarg, NULL, 0);
			break;

		case 'r':
			rtr = 1;
			break;

		case 'e':
			extended = 1;
			break;

		//case VERSION_OPTION:
		//	printf("cansend %s\n", VERSION);
		//	exit(0);
		default:
			fprintf(stderr, "Unknown option %c\n", opt);
			break;
		}
	}

	if (optind == argc) {
		print_usage(basename(argv[0]));
		exit(0);
	}

	if (argv[optind] == NULL) {
		fprintf(stderr, "No Interface supplied\n");
		exit(-1);
	}
	interface = argv[optind];

	printf("interface = %s, family = %d, type = %d, proto = %d\n",
	       interface, family, type, proto);

	s = socket(family, type, proto);
	if (s < 0) {
		perror("socket");
		return 1;
	}

	addr.can_family = family;
	strcpy(ifr.ifr_name, interface);
	if (ioctl(s, SIOCGIFINDEX, &ifr)) {
		perror("ioctl");
		return 1;
	}
	addr.can_ifindex = ifr.ifr_ifindex;

	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		perror("bind");
		return 1;
	}

	for (i = optind + 1; i < argc; i++) {
		frame.data[dlc] = strtoul(argv[i], NULL, 0);
		dlc++;
		if (dlc == 8)
			break;
	}
	frame.can_dlc = dlc;

    extended = 0;
	if (extended) {
		frame.can_id &= CAN_EFF_MASK;
		frame.can_id |= CAN_EFF_FLAG;
	} else {
		frame.can_id &= CAN_SFF_MASK;
	}

	if (rtr)
		frame.can_id |= CAN_RTR_FLAG;

	if (verbose) {
		printf("id: %x ", frame.can_id);
		printf("dlc: %d\n", frame.can_dlc);
		for (i = 0; i < frame.can_dlc; i++)
			printf("0x%02x ", frame.data[i]);
		printf("\n");
	}


    //int sendByte = sendToTecan(1,strBuff,lenStr,s);
    
	memset(strBuff,0,1024);
	
	int sendByte = 0;
	strBuff[0] = 0x23;
	strBuff[1] = 0x01;
	strBuff[2] = 0x01;
	char * strRet = fgets((char *)(&strBuff[3]),1020,fp);
	printf("string from file:%s,len:%d\n",(char *)(&strBuff[3]),strlen((char *)(&strBuff[3])));

	lenStr = strlen((char *)(&strBuff[3]));
	//strBuff[lenStr-1] = '\0';
	//lenStr += 2;//- /n  + 3
	int bytesOnce = 0;
	i = 0;
	unsigned int sumOnce = 0;
	unsigned int sumAll = 0x02;
	sumAll += calcStrSum(lenStr-1,&strBuff[3]);

	strBuff[lenStr+2] = sumAll & 0x00ff;
	strBuff[lenStr+3] = 0x5C;
	lenStr += 4;
	while(lenStr>0)
	{ 
		sumOnce = 0;     
        
		bytesOnce = sendString(frame.can_id,lenStr, strBuff,s,&sumOnce);
        //sumAll += sumOnce;
		sendByte += bytesOnce;
        printf("send %d bytes %dth time\n",bytesOnce,i++);
		memset(strBuff,0,1024);
	    strBuff[0] = 0x23;
	    strBuff[1] = 0x01;
	    strBuff[2] = 0x01;
		strRet = fgets((char *)(&strBuff[3]),1020,fp);
        
		if(!strRet)
		{
			printf("read string from file failed\n");
			// strBuff[0] = sumAll & 0x00ff;
			// strBuff[1] = 0x5C;
			// lenStr = 2;
			// usleep(2000);
			// bytesOnce = sendString(frame.can_id,lenStr, strBuff,s,&sumOnce);
            // //sumAll += sumOnce;
		    // sendByte += bytesOnce;
            // printf("send %d bytes %dth time\n",bytesOnce,i++);
			break;
		}
      
		lenStr = strlen((char *)(&strBuff[3]));
        printf("string from file:%s,len:%d\n",(char*)strBuff,lenStr);
        sumAll = 0x02;
		sumAll += calcStrSum(lenStr-1,&strBuff[3]);
        strBuff[lenStr+2] = sumAll & 0x00ff;
	    strBuff[lenStr+3] = 0x5C;
	    lenStr += 4;
		// if(!feof(fp))
		// {
        //     lenStr -= 1;
		// }
		// else
		// {
		// 	strBuff[lenStr-1] = sumAll & 0x00ff;
		// 	strBuff[lenStr] = 0x5C;
		// 	lenStr += 1;
		// }		
 
	}

	printf("send out %d bytes\n",sendByte);  
	
	fclose(fp);

	close(s);
	return 0;
}
